package DBSystem.analyze;

import java.io.IOException;
import java.util.ArrayList;

import java_cup.runtime.Symbol;

public class Parser {
	private int currentState=0;
	private SQLexer lexer = null;
	
	public Parser (SQLexer lexer) {
		this.lexer = lexer;
	}

	public Object parse() {
		return parse(null);
	}
	
	private Object parse (Object returnValue) {
		Symbol token = null;
			try {
				token = lexer.next_token();
			} catch (IOException e) {
				e.printStackTrace();
			}
			//System.out.println("State: "+currentState+" token:"+token.sym+" value:"+token.value);
			
			if (currentState==0) { //Start
				if (token.sym == Sym.SELECT) {
					currentState = 1;
					Select select = new Select();
					return parse(select);
				}
				if (token.sym == Sym.CREATE) {
					currentState = 8;
					Create create = new Create();
					return parse(create);
				}
				if (token.sym == Sym.DROP){ 
					currentState = 6; 
					Drop drop = new Drop();
					return parse(drop); 
				}
				if (token.sym == Sym.INSERT){ 
					currentState = 14; 
					Insert insert = new Insert();
					return parse(insert); 
				}
			}
			
			if (currentState==1){ //SELECT
				if (token.sym == Sym.ASTERISK) {
					currentState = 2;
					Select select_ast = (Select)returnValue;
					select_ast.selectAll = true;
					return parse(select_ast);
				}
				return "Error: missing column specifier";
			}
			
			if (currentState==2){ //SELECT *
				if (token.sym == Sym.FROM) {
					currentState = 3;
					Select select_ast_from = (Select)returnValue;
					return parse(select_ast_from);
				}
				return "Error: missing FROM";
			}
			
			if (currentState==3){ //SELECT _ FROM
				if (token.sym == Sym.ID) {
					currentState = 4;
					Select select_ast_from_name = (Select)returnValue;
					select_ast_from_name.tablename = (String)token.value;
					return parse(select_ast_from_name);
				}
				return "Error: missing tablename";
			}
			
			if (currentState==4){ //searching semicolon
				if (token.sym == Sym.SEMI) {
					currentState = 5;
					return parse(returnValue);
				}
				return "Error: missing ;";
			}
			
			if (currentState==5) {
				return returnValue;
			}
			
			if (currentState==6){ //Drop
				if (token.sym ==Sym.TABLE){ 
					currentState = 7;
					Drop drop_ast = (Drop)returnValue;
					return parse (drop_ast);
				}
				return "Error: missing keyword TABLE";
			}
			
			if (currentState==7){ //DROP TABLE
				if (token.sym ==Sym.ID) {
					currentState=4;
					Drop drop_table = (Drop)returnValue;
					drop_table.tablename = (String)token.value;
					return parse(drop_table);
				}
				return "Error: specifiy the table to drop";
			}

			if (currentState==8) { //CREATE
				if (token.sym == Sym.TABLE) {
					currentState = 9;
					return parse(returnValue);
				}
				return "Error: missing TABLE";
			}
			
			if (currentState==9) { //CREATE TABLE
				if (token.sym == Sym.ID) {
					currentState = 10;
					Create create = (Create)returnValue;
					create.tablename = (String)token.value;
					return parse(create);
				}
				return "Error: no name for the new table specified";
			}
			
			if (currentState==10) { //CREATE TABLE tablename
				if (token.sym == Sym.LBRACK) {
					currentState = 11;
					return parse(returnValue);
				}
				return "Error: missing (";
			}
			
			if (currentState==11) {
				//CREATE TABLE tablename (
				//CREATE TABLE tablename (DTYPE attrname1, ... , 
				if (token.sym == Sym.DTYPE) {
					currentState = 12;
					Create create = (Create)returnValue;
					if (create.attributes == null){
						create.attributes = new ArrayList<CreateAttribute>();
					}
					CreateAttribute ca = new CreateAttribute();
					ca.datatype = (String)token.value;
					create.attributes.add(ca);
					return parse(create);
				}
				return "Error: expecting INT|DOUBLE|CHAR for new attribute)";
			}
			
			if (currentState==12) { //CREATE TABLE tablename (DTYPE
				if (token.sym == Sym.ID) {
					currentState = 13;
					Create create = (Create)returnValue;
					int lastIndex = create.attributes.size()-1;
					CreateAttribute ca = create.attributes.get(lastIndex);
					ca.name = (String)token.value;
					return parse(create);
				}
				return "Error: expecting name for attribute";
			}
			
			if (currentState==13) { //CREATE TABLE tablename (DTYPE attrname
				if (token.sym == Sym.KOMMA) {
					currentState = 11;
					return parse(returnValue);
				}
				if (token.sym == Sym.RBRACK) {
					currentState = 4;
					return parse(returnValue);
				}
				return "Error: expecting name for attribute";
			}

			if (currentState==14) { //INSERT
				if (token.sym == Sym.INTO) {
					currentState = 15;
					return parse(returnValue);
				}
				return "Error: missing INTO";
			}

			if (currentState==15) { //INSERT INTO
				if (token.sym == Sym.ID) {
					currentState = 16;
					Insert insert = (Insert)returnValue;
					insert.tablename = (String)token.value;
					return parse(insert);
				}
				return "Error: missing tablename where to insert";
			}

			if (currentState==16) { //INSERT INTO ID
				if (token.sym == Sym.LBRACK) {
					currentState = 17;
					return parse(returnValue);
				}
				return "Error: (";
			}

			if (currentState==17) { //INSERT INTO ID (
				if (token.sym == Sym.ID) {
					currentState = 18;
					Insert insert = (Insert)returnValue;
					if (insert.attributes == null) {
						insert.attributes = new ArrayList<String>();
					}
					insert.attributes.add((String)token.value);
					return parse(insert);
				}
				return "Error: missing attribute name";
			}

			if (currentState==18) { //INSERT INTO ID ( ID
				if (token.sym == Sym.KOMMA) {
					currentState = 17;
					return parse(returnValue);
				}
				if (token.sym == Sym.RBRACK) {
					currentState = 19;
					return parse(returnValue);
				}
				return "Error: expecting , or )";
			}

			if (currentState==19) { //INSERT INTO ID ( ID, ID, ...)
				if (token.sym == Sym.VALUES) {
					currentState = 20;
					return parse(returnValue);
				}
				return "Error: expecting VALUES";
			}

			if (currentState==20) { //INSERT INTO ID ( ID, ID, ...) VALUES
				if (token.sym == Sym.LBRACK) {
					currentState = 21;
					return parse(returnValue);
				}
				return "Error: expecting (";
			}

			if (currentState==21) { //INSERT INTO ID ( ID, ID, ...) VALUES (
				if (	token.sym == Sym.INT
						|| token.sym == Sym.DOUBLE
						|| token.sym == Sym.CHAR) {
					currentState = 22;
					Insert insert = (Insert)returnValue;
					if (insert.values == null) {
						insert.values = new ArrayList<String>();
					}
					insert.values.add((String)token.value);
					return parse(insert);
				}
				return "Error: expecting an integer number or a double number or a character";
			}

			if (currentState==22) { //INSERT INTO ID ( ID, ID, ...) VALUES (INT, ...
				if (token.sym == Sym.KOMMA) {
					currentState = 21;
					return parse(returnValue);
				}
				if (token.sym == Sym.RBRACK) {
					currentState = 4;
					return parse(returnValue);
				}
				return "Error: expecting , or )";
			}
			
			return "Error: something is missing.";
			
	}
}
